package com.gopay.gass.service.impl;

import java.math.BigDecimal;
import java.util.Date;

import javax.annotation.Resource;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;

import com.gopay.common.cipher.utils.LoggerMaskUtils;
import com.gopay.common.constants.bank.BisBankBusinessProd;
import com.gopay.common.constants.bank.BisBankInterfaceChannel;
import com.gopay.common.domain.bank.BcdlMessage;
import com.gopay.common.domain.bank.BcdlResult;
import com.gopay.common.util.DateUtils;
import com.gopay.common.util.JsonUtils;
import com.gopay.common.util.ReadingPropertyFiles;
import com.gopay.gass.base.common.GassOrderView;
import com.gopay.gass.constants.BCFlag;
import com.gopay.gass.constants.NotifyStatus;
import com.gopay.gass.constants.OrderSource;
import com.gopay.gass.constants.RespType;
import com.gopay.gass.constants.SameBank;
import com.gopay.gass.constants.SameCity;
import com.gopay.gass.constants.Urgent;
import com.gopay.gass.domain.GassMainOrder;
import com.gopay.gass.domain.GassOrderDtl;
import com.gopay.gass.exception.GassServiceException;
import com.gopay.gass.message.GassPayReqMessage;
import com.gopay.gass.message.GassPayRespMessage;
import com.gopay.gass.message.ResultCode;
import com.gopay.gass.service.GassOrderService;
import com.gopay.gass.service.GassPayRequestService;
import com.gopay.remote.bank.BcdlInteractRemoteService;

/**
 * Created by HJY on 2015/3/20.
 */
public abstract class GassPayRequestServiceImpl implements GassPayRequestService {
    protected final Logger logger = LoggerFactory.getLogger(getClass());

    @Resource(name = "bankBcdlClient")
    private BcdlInteractRemoteService bankBcdlClient;

    @Resource(name = "gassOrderService")
    protected GassOrderService gassOrderService;
    
    @Value("#{bankConfig['gass_notify_url']}")
    private  String gassNotifyUrl;

    protected GassMainOrder checkMainMsg(GassPayReqMessage reqMsg) throws GassServiceException {
        GassMainOrder main = new GassMainOrder();
        if(StringUtils.isEmpty(reqMsg.getGopayOrderId())){
            throw new GassServiceException("订单号为空");
        }
        main.setGopayOrderId(reqMsg.getGopayOrderId());
        String orderSource = StringUtils.isEmpty(reqMsg.getOrderSource())? OrderSource.New.toString():reqMsg.getOrderSource();
        if(!(StringUtils.equals(orderSource, OrderSource.New.toString()) || StringUtils.equals(orderSource,OrderSource.Old.toString()))){
            throw new GassServiceException("订单来源错误");
        }
        main.setOrderSource(orderSource);
        if(reqMsg.getOrderReqTm() == null){
            throw new GassServiceException("订单申请时间为空");
        }
        main.setOrderReqTm(reqMsg.getOrderReqTm());
        String respType = StringUtils.isEmpty(reqMsg.getRespType())? RespType.Sync.toString():reqMsg.getRespType();
        if(!(StringUtils.equals(respType, RespType.Asyn.toString()) || StringUtils.equals(respType,RespType.Sync.toString()))){
            throw new GassServiceException("响应方式为空");
        }
        main.setRespType(respType);
        if(StringUtils.equals(respType,RespType.Asyn.toString())){
            if(StringUtils.isEmpty(reqMsg.getNotifyUrl()))
                throw new GassServiceException("通知地址为空");
            main.setNotifyStatus(NotifyStatus.NO.toString());
        }
        main.setPayBankCode(reqMsg.getPayBankCode());
        main.setNotifyUrl(reqMsg.getNotifyUrl());
        main.setCreatedTs(new Date());
        main.setNotifyCount(0);
        main.setStlmStatus(ResultCode.NO.getValue());
        return main;
    }

    protected GassOrderDtl checkOrderDtlMsg(GassPayReqMessage reqMsg) throws GassServiceException {
        GassOrderDtl dtl = new GassOrderDtl();
        if(reqMsg.getOrderAmt() == null || reqMsg.getOrderAmt().compareTo(new BigDecimal(0)) < 1){
            throw new GassServiceException("订单金额为空");
        }
        dtl.setOrderAmt(reqMsg.getOrderAmt());

        if(StringUtils.isEmpty(reqMsg.getIsUrgent()))
            reqMsg.setIsUrgent(Urgent.YES.toString());

        if(!(StringUtils.equals(reqMsg.getIsUrgent(), Urgent.YES.toString()) || StringUtils.equals(reqMsg.getIsUrgent(),Urgent.NO.toString()))){
            throw new GassServiceException("是否紧急错误");
        }
        dtl.setIsUrgent(reqMsg.getIsUrgent());
        if(!(StringUtils.equals(reqMsg.getBcFlag(), BCFlag.BC_FLAG_C.toString()) || StringUtils.equals(reqMsg.getBcFlag(),BCFlag.BC_FLAG_P.toString()))){
            throw new GassServiceException("对公对私错误");
        }
        dtl.setBcFlag(reqMsg.getBcFlag());

        if(StringUtils.isEmpty(reqMsg.getRecvBankName())){
            throw new GassServiceException("收款银行为空");
        }
        dtl.setRecvBankName(reqMsg.getRecvBankName());

/*        if(StringUtils.isEmpty(reqMsg.getRecvBankCode())){
            throw new GassServiceException("recvBankCode is null");
        }*/
        dtl.setRecvBankCode(reqMsg.getRecvBankCode());

        if(StringUtils.isEmpty(reqMsg.getRecvBankAcctName())){
            throw new GassServiceException("收款银行账户名为空");
        }
        dtl.setRecvBankAcctName(reqMsg.getRecvBankAcctName());


        if(StringUtils.isEmpty(reqMsg.getRecvBankAcctNum())){
            throw new GassServiceException("收款银行帐号为空");
        }
        dtl.setRecvBankAcctNum(reqMsg.getRecvBankAcctNum());

        if(StringUtils.isEmpty(reqMsg.getRecvBankProvinceName())){
            //throw new GassServiceException("收款行省份为空");
        	reqMsg.setRecvBankProvinceName("北京市");//手机钱包自动结算没有相关信息报错，因此写死
        }
        dtl.setRecvBankProvinceName(reqMsg.getRecvBankProvinceName());

        if(StringUtils.isEmpty(reqMsg.getRecvBankProvinceCode())){
            //throw new GassServiceException("recvBankProvinceCode is null");
        	reqMsg.setRecvBankProvinceCode("01");//手机钱包自动结算没有相关信息报错，因此写死
        }
        dtl.setRecvBankProvinceCode(reqMsg.getRecvBankProvinceCode());

        if(StringUtils.isEmpty(reqMsg.getRecvBankCityName())){
            //throw new GassServiceException("收款行地市为空");
        	reqMsg.setRecvBankCityName("北京市");//手机钱包自动结算没有相关信息报错，因此写死
        }
        dtl.setRecvBankCityName(reqMsg.getRecvBankCityName());

        /*if(StringUtils.isEmpty(reqMsg.getRecvBankCityCode())){
            throw new GassServiceException("recvBankCityCode is null");
        }*/
        dtl.setRecvBankCityCode(reqMsg.getRecvBankCityCode());

        dtl.setRecvBankBranchCode(reqMsg.getRecvBankBranchCode());
        dtl.setRecvBankBranchName(reqMsg.getRecvBankBranchName());
        String sameCity = SameCity.NO.toString();
        if(StringUtils.equals(reqMsg.getRecvBankProvinceCode(),"01") || (reqMsg.getRecvBankProvinceName()!= null && reqMsg.getRecvBankProvinceName().indexOf("北京") !=-1)){
            sameCity = SameCity.YES.toString();
        }
        dtl.setIsSameCity(sameCity);
        dtl.setCreatedTs(new Date());
        return dtl;
    }
    
    @Override
    public GassPayRespMessage processReq(GassPayReqMessage reqMsg){
        logger.info("------[银企直连调用"+getBankName()+"]start-------orderId:"+reqMsg.getGopayOrderId());
        GassOrderView orderView = null;
        try {
            orderView = checkAndSaveOrder(reqMsg);
        } catch (GassServiceException e) {
            e.printStackTrace();
            return createRespMsg("", ResultCode.FAILED, e.getErrorMsg());
        }
        logger.info("------[银企直连调用"+getBankName()+"]saved-------orderId:"+reqMsg.getGopayOrderId());
        return pay(orderView.getMainOrder(), orderView.getOrderDtl());
    }

    /**
     * 银企直连公共报文
     * @param main
     * @param dtl
     * @return
     */
    protected BcdlMessage createBaseBcdlMessage(GassMainOrder main,GassOrderDtl dtl){
        BcdlMessage message = new BcdlMessage();
        message.setGopayAuthTime(DateUtils.format(main.getOrderReqTm()));
        message.setAmount(dtl.getOrderAmt());
        message.setEmergency(Integer.parseInt(dtl.getIsUrgent()));/* 加急标志 0加急 1不加急*/
        message.setRecvBankAcctName(dtl.getRecvBankAcctName());
        message.setRecvBankAcctNum(dtl.getRecvBankAcctNum());
        message.setDcblType(Integer.parseInt(dtl.getBcFlag()));//对公对私类型  1-对公，2-对私
        message.setRecvBankProvName(dtl.getRecvBankProvinceName());//收款方省代码、名称
        message.setRecvBankProvNo(dtl.getRecvBankProvinceCode());
        message.setRecvBankCityName(dtl.getRecvBankCityName());
        message.setRecvBankCityCode(dtl.getRecvBankCityCode());
        message.setBank(main.getPayBankCode());
        message.setIsSameCity(Integer.parseInt(dtl.getIsSameCity()));/* 1同城2异地标示 */
        message.setOrderId(main.getGopayOrderId());
        message.setGopayBankOrderNo(main.getGopayOrderId());
        message.setBankOrderType("00");
        message.setSysIOFlg(Integer.parseInt(dtl.getIsSameBank()));/* 1系统内、0外标志 */
        message.setNotifyUrl(gassNotifyUrl);
        message.setRecvBankName(dtl.getRecvBankName());//收款方银行名称
        message.setRecvBankCode(dtl.getRecvBankCode());//收款方行号
        message.setBankBusProd(BisBankBusinessProd._09); 
        message.setBankIntrChann(BisBankInterfaceChannel._00);//接口通道默认00 直连
        return message;
    }

    /**
     * 子类实现，不同银行组建不同报文
     * @param main
     * @param dtl
     * @return
     */
    protected abstract BcdlMessage buildBcdlMessage(GassMainOrder main, GassOrderDtl dtl);
    
    /**
     * 银企直连重构
     * 此处BIS只返回是否受理成功，所有银行一致
     * 由BIS通过后台通知告知Gass银行付款的真实结果：付款成功/付款失败
     * @param main
     * @param dtl
     * @return
     */
    protected GassPayRespMessage pay(GassMainOrder main,GassOrderDtl dtl){
        String gassId = main.getGassId();
        ResultCode resultCode = ResultCode.FAILED;
        String resultMsg = "付款失败";
        BcdlMessage message = null;
        try{
        	message = buildBcdlMessage(main, dtl);
        	/**
        	 * modified by zyt, 2017-2-22，修改输出日志中的全卡号做掩码显示
        	 */
        	logger.error("BcdlMessage = " + LoggerMaskUtils.maskString(ToStringBuilder.reflectionToString(message)));
        } catch(Exception e) {
        	e.printStackTrace();
            return createRespMsg(gassId, resultCode, "组装报文失败");
        }
        BcdlResult result = null;
        try {
            //调用银企直连
            result = bcdlPay(message);
        } catch (Exception e) {
            e.printStackTrace();
            return createRespMsg(gassId, resultCode, "调用银企直连失败");
        }
        if(result != null){
            if(result.isSuccess()){//受理成功
                resultCode = ResultCode.ACCEPTED;
                resultMsg = "付款已受理";
            }else{//受理失败：BIS返回失败原因
            	resultMsg = result.getErrorMsg();
            }
        }else{
            resultMsg = "银企直连返回空";
        }
        main.setStlmDes(resultMsg);
        main.setStlmStatus(resultCode.getValue());
        main.setOrderRespTm(new Date());
        main.setLastUpdTs(new Date());
        gassOrderService.updateMainOrder(main);
        logger.info("------[银企直连调用"+getBankName()+"]pay-------orderId:"+main.getGopayOrderId()+" resultMsg:"+resultMsg);
        return createRespMsg(gassId, resultCode, resultMsg);
    }
    
    protected BcdlResult bcdlPay(BcdlMessage bcdlMessage){
        BcdlResult result = null;
        try {
        	/**
        	 * modified by zyt, 2017-2-22，修改输出日志中的全卡号做掩码显示，json的输出格式改为tostring的格式
        	 */
            logger.info("bcdl pay orderId:"+bcdlMessage.getOrderId()+" request info :"+ LoggerMaskUtils.maskString(bcdlMessage.toString()));
            String flag = ReadingPropertyFiles.getPropertyElementByKey("config", "enableOnlinePayFlag");
            logger.info("读取配置：是否开启线上支付[" + flag + "]");
            if(Boolean.valueOf(flag)) {
            	result =  bankBcdlClient.eft(bcdlMessage);
            } else {
            	result = new BcdlResult();
            	result.setSuccess(true);
            }
            StringBuffer sb = new StringBuffer("bcdl pay orderId:"+bcdlMessage.getOrderId()+" response info :");
            if(result == null){
                sb.append(" result is null");
                logger.error(sb.toString());
            }else{
                sb.append(result.isSuccess() +" -- "+result.getBankRetMsg());
                logger.info(sb.toString());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    protected GassPayRespMessage createRespMsg(String responseId,ResultCode resultCode,String resultMsg){
        GassPayRespMessage message = new GassPayRespMessage();
        message.setResponseId(responseId);
        message.setResultCode(resultCode);
        message.setResultMsg(resultMsg);
        return message;
    }


    protected GassOrderView checkAndSaveOrder(GassPayReqMessage reqMsg) throws GassServiceException{
        GassMainOrder main = checkMainMsg(reqMsg);
        GassOrderDtl dtl = checkOrderDtlMsg(reqMsg);

        dtl.setIsSameBank(getSameBank(reqMsg.getRecvBankName()).toString());

        //订单保存
        main = gassOrderService.saveNewOrder(main,dtl);

        return new GassOrderView(main,dtl);
    }

    /**
     * 子类实现，返回银行中文名
     * @return
     */
    protected abstract String getBankName();
    
    protected SameBank getSameBank(String recvBankName){
        return  null;
    }

}
